package org.maxgroundstation.groundstation.comm.service.gps;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import javax.swing.SwingUtilities;

import org.maxgroundstation.groundstation.comm.service.Service;
import org.maxgroundstation.groundstation.comm.service.ServiceCommunication;
import org.maxgroundstation.groundstation.comm.service.ServiceDataFrame;
import org.maxgroundstation.groundstation.comm.service.ServiceUtil;

/**
 * The rover GPS service.
 * @author Scott Davis
 * 
 * Copyright (C) 2010  Scott Davis
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
public class GpsService extends Service {

    // Static members
    public static final String SERVICE_ID = ServiceUtil.getServiceID("gps");
    public static final String TYPE = "gps";
    
    // Directory to store point of interest data.
    private static final String POI_DIR = System.getProperty("user.home") + File.separator + 
        "max_groundstation" + File.separator + "poi";
    
    // Service event type.
    public static final String GPS_UPDATE = "gps update";
    public static final String POI_UPDATE = "poi update";
    
    // Data members
    private Map<String, String> gpsMap;
    private GpsDataLogger logger;
    private List<PointOfInterest> poiList;
    
    /**
     * Constructor
     * @param comm the service communication.
     */
    public GpsService(ServiceCommunication comm) {
        // Use Service constructor
        super(comm);
        
        // Initialize data members.
        gpsMap = new HashMap<String, String>();
        logger = new GpsDataLogger(this);
        poiList = loadPointsOfInterest();
        
        // Fire POI update service event.
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                fireServiceEvent(POI_UPDATE, getPointsOfInterest());
            }
        });
    }
    
    /**
     * Gets the gps map.
     * @return gps map.
     */
    public Map<String, String> getGpsMap() {
        return new HashMap<String, String>(gpsMap);
    }
    
    /**
     * Gets the GPS data logger.
     * @return logger.
     */
    public GpsDataLogger getLogger() {
        return logger;
    }
    
    @Override
    public String getID() {
        return SERVICE_ID;
    }

    @Override
    public void handleResponse(ServiceDataFrame dataFrame) {
        // Parse data string.
        String dataString = dataFrame.getDataString().trim();
        //System.out.println("GPS update: " + dataString);
        StringTokenizer st1 = new StringTokenizer(dataString, ",");
        while(st1.hasMoreTokens()) {
            String keyValuePair = st1.nextToken();
            StringTokenizer st2 = new StringTokenizer(keyValuePair, "=");
            String key = st2.nextToken();
            String valueString = st2.nextToken();
            gpsMap.put(key, valueString);
        }
        
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                fireServiceEvent(GPS_UPDATE, new HashMap<String, String>(gpsMap));
            }
        });
    }

    @Override
    public void initialize() {
        // Do nothing
    }

    @Override
    public boolean isDefaultService() {
        return false;
    }

    @Override
    public boolean isSubscribable() {
        return true;
    }
    
    /**
     * Gets a list of points of interest.
     * @return list
     */
    public List<PointOfInterest> getPointsOfInterest() {
        return new ArrayList<PointOfInterest>(poiList);
    }
    
    /**
     * Adds a point of interest.
     * @param poi the point of interest.
     */
    public void addPointOfInterest(PointOfInterest poi) {
        poiList.add(poi);
        savePointsOfInterest();
        
        // Fire POI update service event.
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                fireServiceEvent(POI_UPDATE, getPointsOfInterest());
            }
        });
    }
    
    /**
     * Commits an edit to a point of interest.
     * @param poi the edited point of interest.
     */
    public void commitPointOfInterestEdit(PointOfInterest poi) {
        savePointsOfInterest();
        
        // Fire POI update service event.
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                fireServiceEvent(POI_UPDATE, getPointsOfInterest());
            }
        });
    }
    
    /**
     * Deletes a point of interest.
     * @param poi the point of interest to delete.
     */
    public void deletePointOfInterest(PointOfInterest poi) {
        if (poiList.contains(poi)) {
            poiList.remove(poi);
            
            // Delete all point of interest video snapshots.
            Iterator<String> i = poi.getSnapshotFileNames().iterator();
            while (i.hasNext()) {
                String filename = i.next();
                File videoSnapshotFile = new File(POI_DIR + File.separator + filename);
                if (videoSnapshotFile.exists()) {
                    videoSnapshotFile.delete();
                }
            }
        }
        savePointsOfInterest();
        
        // Fire POI update service event.
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                fireServiceEvent(POI_UPDATE, getPointsOfInterest());
            }
        });
    }
    
    /**
     * Save points of interest list to XML file.
     */
    private void savePointsOfInterest() {
        PointOfInterestUtil.savePointsOfInterest(poiList);
    }
    
    /**
     * Load points of interest list from XML file.
     */
    private List<PointOfInterest> loadPointsOfInterest() {
        return PointOfInterestUtil.loadPointsOfInterest();
    }

    @Override
    public String getType() {
        return TYPE;
    }
}